#include "operacionCrearIndSec.h"

OperacionCrearIndSec::OperacionCrearIndSec(ArchivoDatos * a, IndiceSec * ind_sec, std::string& formato_maestro, unsigned int num ){
	arch_maestro = a;
	arch_sec = ind_sec;
	formato_archivo_primario = formato_maestro;
	num_campo_sec = num;
	
} 

std::string OperacionCrearIndSec::get_formato_sec(std::string formato, int pos){
	formato.erase(0,1);
	formato.erase(formato.size() - 1, 1);
	std::vector<std::string> cortados = Parser::split_parametros(formato,',');
	
	std::string retorno = "[";
	retorno += cortados[pos];
	retorno += ",";
	retorno += cortados[0];
	retorno +="]";
	
	return retorno;
	
}

void OperacionCrearIndSec::validar_ind_sec(ArchivoDatos * maestro, std::string formato, int num_campo_sec){
	
	TipoStruct * reg_base_maestro = maestro->generar_reg_base(formato);
	
	if( (unsigned int)num_campo_sec >= (reg_base_maestro->get_tamanio() ) ){
		delete reg_base_maestro;
		throw ExcepSintaxisParser("Error - No se puede crear el indice secundario ya que el campo no pertenece al archivo");
	}
	
	if( ((*reg_base_maestro)[num_campo_sec].get_codigo_tipo() != STRING) && 
		((*reg_base_maestro)[num_campo_sec].get_codigo_tipo() != INT) ){
		delete reg_base_maestro;
		throw ExcepSintaxisParser("Error - No se puede crear el indice secundario con un campo que no sea int o string");		
	}
	delete reg_base_maestro;
}
Operacion * OperacionCrearIndSec::construir(std::string param){
	Operacion * _return = NULL;
	
	std::vector<std::string> params = Parser::split_parametros(param, ';');
	if( params.size() == 4 ){
		std::string para_crear;
		//Llamo a la operacion crear para fabricar el maestro
		para_crear = params[0] + ";" + params[1] + ";" + params[2];
		OperacionCrear * op = (OperacionCrear*)OperacionCrear::construir(para_crear);
		if(op != NULL){
			//Si estaba bien de sintaxis, le saco el archivo maestro
			//y la elimino
			ArchivoDatos * archivo_maestro = op->get_archivo();
			std::string formato_maestro = op->get_formato();
			delete op;
			if( archivo_maestro->get_tipo_archivo() == SECUENCIAL ){
				delete archivo_maestro;
				throw ExcepSintaxisParser("Error - El archivo secuencial no permite indice secundario");
			}
			//obtengo el tipo de de indice secundario asi como tambien
			//el campo por el cual indexa			
			size_t pos = params[3].find_first_of("[");
			if( pos != std::string::npos ){
				std::string tipo_ind = params[3].substr(0, pos);
				if( (params[3][params[3].size() - 1]) == ']'  ){
					std::string num_campo = params[3].substr(pos + 1, params[3].size() - pos - 2);
					int val = 0;
					if( Parser::convertir_a_int(num_campo, val) ){
						if( val > 0){
							try{
								validar_ind_sec(archivo_maestro, formato_maestro, val);
							}
							catch(ExcepSintaxisParser &e){
								delete archivo_maestro;
								throw e;
							}
							IndicesFactory fab;
							std::string nom_ind_sec = archivo_maestro->get_nombre();
							nom_ind_sec.append(".sec");
							IndiceSec * ind_sec;
							try{
								ind_sec = fab.crear_archivo( tipo_ind ,nom_ind_sec,archivo_maestro->get_tam_bloque(), archivo_maestro->get_tam_indice(), val); 			
							}catch(ExcepSintaxisParser &e){
								delete archivo_maestro;
								throw e;
							}
							if( ind_sec != NULL ){
								try{
									size_t pos = params[1].find_first_of('[');
									std::string formato;
									if( pos != std::string::npos ){
										formato = params[1].substr(pos, params.size() - pos - 1);				
									}
									else
										throw ExcepSintaxisParser("Error - Sintaxis incorrecta");
																		
									
								}
								catch(ExcepSintaxisParser &e){
									delete archivo_maestro;
									throw e;
									
								}
								
								_return = new OperacionCrearIndSec(archivo_maestro, ind_sec, formato_maestro, val);
							}
						}
						else{
							delete archivo_maestro;
							throw ExcepSintaxisParser("Error - El indice secundario debe ser distinto de 0");
						}
					}
					else{
						delete archivo_maestro;
						throw ExcepSintaxisParser("Error - Numero de campo para el indice secundario no es numerico");
					}
				}
				else{
					delete archivo_maestro;
					throw ExcepSintaxisParser("Error - Parametro par el indice incorrecto. Falto cerrar el '['");
				}
			}
			else{
				delete archivo_maestro;
				throw ExcepSintaxisParser("Error - Parametro para el indice incorrecto. Debe comenzar con '['");
			}
			
		}
	}
	return _return;
	
	
}
		
OperacionCrearIndSec::~OperacionCrearIndSec(){

}
		
void OperacionCrearIndSec::ejecutar(Modelo *modelo){
	//std::string mensaje = "Se debe ejecutar la creacion con indice secundario. No esta implementado en esta etapa. RES = 0";
	//(*Logger::get_instance()) << mensaje;
	//( Debug::get_instance() )->mostrar_mensaje(mensaje);
	
	try{
		
		std::string formato_sec = get_formato_sec(formato_archivo_primario, num_campo_sec);
		this->arch_maestro->set_indice(this->arch_sec);
		this->arch_maestro->crear(this->formato_archivo_primario);
		try{
			this->arch_sec->crear(formato_sec);
		}
		catch(ExcepSintaxisParser &e){
			this->arch_maestro->agregar_observador(Buffer::get_instance());
			this->arch_maestro->eliminar();
			throw e;	
		}
		modelo->agregar_archivo(this->arch_maestro);
		std::string mensaje = "Se creo correctamente el archivo "+this-> arch_maestro->get_nombre() +"con indice secundario. RES = 1";
		(*Logger::get_instance()) << mensaje;
		( Debug::get_instance() )->mostrar_mensaje(mensaje);
	}
	catch( ExcepSintaxisParser &e){
		delete this->arch_maestro;
		//delete this->arch_sec;
		std::string error = e.what();
		error.append("RES = 0");
		(*Logger::get_instance()) << error;
		( Debug::get_instance() )->mostrar_mensaje(error);
	}
	catch(ExcepCreandoArch &e){
		delete this->arch_maestro;
		//delete this->arch_sec;
		std::string error = e.what();
		error.append("RES = 0");
		(*Logger::get_instance()) << error;
		( Debug::get_instance() )->mostrar_mensaje(error);
	}
	catch( ExcepBloqueTam &e){
		std::string error = e.what();
		error.append("RES = 0");
		delete this->arch_maestro;
		//delete this->arch_sec;
		(*Logger::get_instance()) << error;
		( Debug::get_instance() )->mostrar_mensaje(error);
	}
}
